import * as THREE from "three";
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
//引入性能监视器stats.js
import Stats from "three/addons/libs/stats.module.js";

import { GUI } from "dat.gui";

// 格式：add(控制对象，对象具体属性，其他参数)

const gui = new GUI();

// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
console.log("查看当前屏幕设备像素比", window.devicePixelRatio);

const stats = new Stats();

// stats.domElement显示：渲染帧率  刷新频率,一秒渲染次数
// stats.setMode(0);//默认模式
//stats.domElement显示：渲染周期 渲染一帧多长时间(单位：毫秒ms)
stats.setMode(1);

// 创建场景
const scene = new THREE.Scene();

//创建一个对象，对象属性的值可以被GUI库创建的交互界面改变
const obj = {
  x: 100,
  y: 100,
  z: 100,
  color: 0x00ffff,
  scale: 0,
  bool: false,
};

//BoxGeometry：长方体
// const geometry = new THREE.BoxGeometry(obj.x, obj.y, obj.z);
// SphereGeometry：球体
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry：圆柱
// const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry：矩形平面
// const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry：圆形平面
// const geometry = new THREE.CircleGeometry(50);

// 基础网格材质 MeshBasicMaterial
// 高光网格材质 MeshPhongMaterial
// 漫反射网格材质 MeshLambertMaterial

//材质对象Material
const material = new THREE.MeshPhongMaterial({
  color: 0x00ffff, //设置材质颜色
  // transparent: true, //开启透明
  // opacity: 0.5, //设置透明度
  // side: THREE.FrontSide, //默认只有正面可见
  // side: THREE.DoubleSide, //两面可见

  shininess: 100, //高光部分的亮度，默认30
  specular: 0x444444, //高光部分的颜色
});

const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh

scene.add(mesh);

// 辅助观察坐标系
// three.js坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴，
// 对于three.js的3D坐标系默认y轴朝上
const axesHelper = new THREE.AxesHelper(150);

// 添加辅助坐标系
scene.add(axesHelper);

// 设置透视相机
// PerspectiveCamera( fov, aspect, near, far )
// fov	相机视锥体竖直方向视野角度	50
// aspect	相机视锥体水平方向和竖直方向长度比，一般设置为Canvas画布宽高比width / height	1
// near	相机视锥体近裁截面相对相机距离	0.1
// far	相机视锥体远裁截面相对相机距离，far-near构成了视锥体高度方向	2000

// 定义相机输出画布的尺寸(单位:像素px)
// const width = 800; //宽度
// const height = 500; //高度

// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度
const height = window.innerHeight; //窗口文档显示区的高度作为画布高度

// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000：远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 8000);

// 设置相机位置
camera.position.set(200, 200, 200);

// // 相机观察mesh位置
// camera.lookAt(mesh.position);
// camera.lookAt(0, 0, 0);
camera.lookAt(1000, 0, 1000);

//点光源：两个参数分别表示光源颜色和光照强度
// 参数1：0xffffff是纯白光,表示光源颜色
// 参数2：1.0,表示光照强度，可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);

// pointLight.intensity = 1.0;//光照强度
// pointLight.decay = 0.0; //设置光源不随距离衰减
pointLight.decay = 1.0; //设置光源距离衰减

// 你可以对比不同光照强度明暗差异(传播同样距离)
pointLight.intensity = 100.0; //光照强度
// pointLight.intensity = 50000.0;//光照强度

//点光源位置 ,放在x轴上
// pointLight.position.set(0, 400, 400);
// pointLight.position.set(100, 60, 50);
pointLight.position.set(100, 50, 75);

// 光源辅助观察
const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);

//环境光:没有特定方向，整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.1);

scene.add(ambient);

// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(80, 100, 50);

// 创建材质子菜单
const matFolder = gui.addFolder("材质");
matFolder.close();
// 材质颜色color
matFolder.addColor(material, "color").onChange(function (value) {
  material.color.set(value);
});
// 材质高光颜色specular
matFolder.addColor(material, "specular").onChange(function (value) {
  material.specular.set(value);
});
// 环境光子菜单
const ambientFolder = gui.addFolder("环境光");
// 环境光强度
ambientFolder.add(ambient, "intensity", 0, 2);

//点光源添加到场景中
// scene.add(pointLight);
scene.add(pointLightHelper);

// 场景添加平行光
scene.add(directionalLight);

// DirectionalLightHelper：可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(
  directionalLight,
  5,
  0xff0000
);
scene.add(dirLightHelper);

// 创建wengl渲染器
const renderer = new THREE.WebGLRenderer({
  // 渲染器锯齿属性.antialias
  antialias: true,
});
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x444444, 1); //设置背景颜色
//设置three.js渲染区域的尺寸(像素px)

renderer.setSize(width, height);

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 启用阻尼效果
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// controls.target.set(1000, 0, 1000);
// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
  renderer.render(scene, camera); //执行渲染操作
  // 浏览器控制台查看相机位置变化
  // console.log("camera.position", camera.position);
});

//执行渲染操作
renderer.render(scene, camera);

// Canvas画布插入到任意HTML元素中
// document.getElementById("webgl").appendChild(renderer.domElement);

document.body.appendChild(renderer.domElement);
document.body.appendChild(stats.domElement);

// 渲染函数
function render() {
  renderer.render(scene, camera); //执行渲染操作
  if (obj.bool) mesh.rotateY(0.01);
  controls.update(); // 必须调用此方法，以便阻尼效果生效
  stats.update(); //requestAnimationFrame循环调用的函数中调用方法update(),来刷新时间
  requestAnimationFrame(render); //请求再次执行渲染函数render，渲染下一帧
}
render();
// 渲染循环
window.onresize = function () {
  // 重置渲染器输出画布canvas尺寸
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
  // 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
  // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
  camera.updateProjectionMatrix();
};

// console.log(THREE);
